package com.service.single.annotation;

import com.alibaba.fastjson.JSONObject;
import com.service.single.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

/**
 * @Author: 一休
 * @Date: 2024/7/16
 * 业务场景，给数据添加锁
 */
@Aspect
@Component
@Slf4j
public class BeforeLockAspect {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Before("@annotation(BeforeLock)")
    public void before(JoinPoint joinPoint) throws IOException {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 用户唯一标识
        String authorization = request.getHeader(HttpHeaders.AUTHORIZATION);
        MethodSignature sign = (MethodSignature) joinPoint.getSignature();
        Method method = sign.getMethod();
        BeforeLock annotation = method.getAnnotation(BeforeLock.class);
        if (ObjectUtils.isEmpty(annotation)) {
            return;
        }
        String code = annotation.code();
        String[] columns = annotation.columns();
        // 定义业务 key
        StringBuilder builder = new StringBuilder();
        builder.append(code);
        String methodName = request.getMethod();
        if (StringUtils.equals(HttpMethod.GET.name(), methodName)) {
            for (String column : columns) {
                builder.append("-");
                String parameter = request.getParameter(column);
                builder.append(parameter);
            }
        }

        if (StringUtils.equals(HttpMethod.POST.name(), methodName)) {
            BufferedReader streamReader = new BufferedReader(new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8));
            StringBuilder responseStrBuilder = new StringBuilder();
            String inputStr;
            while ((inputStr = streamReader.readLine()) != null) {
                responseStrBuilder.append(inputStr);
            }
            JSONObject jsonObject = JSONObject.parseObject(responseStrBuilder.toString());
            for (String column : columns) {
                builder.append("-");
                builder.append(jsonObject.get(column));
            }
        }
        String key = builder.toString();
        log.info(key);
        // 校验是否存在已打开的锁
        String oldKey = redisTemplate.opsForValue().get(authorization);
        if (StringUtils.isNotBlank(oldKey) && !StringUtils.equals(oldKey, key)) {
            redisTemplate.delete(oldKey);
        }
        // 校验是否本人操作
        if (redisTemplate.hasKey(key)) {
            String value = redisTemplate.opsForValue().get(key);
            if (!StringUtils.equals(value, authorization)) {
                Long expireTime = redisTemplate.opsForValue().getOperations().getExpire(key);
                throw new BizException("用户编辑中，暂时不能修改,预计等待时间：" + expireTime);
            }
        }
        redisTemplate.opsForValue().set(authorization, key, 60, TimeUnit.SECONDS);
        // 设置过期时间
        redisTemplate.opsForValue().set(key, authorization, 60, TimeUnit.SECONDS);
    }
}
